#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "avl.h"
#include "dictionary.h"

static node_t **nodes = NULL;
static avl_t *tree = NULL;

void dict_init()
{
    if (tree == NULL)
        tree = avl_create(MAX_PART_SIZE);
}

void dict_delete()
{
    if (tree != NULL) {
        free(nodes);
        nodes = NULL;
        avl_destroy(tree);
        tree = NULL;
    }
}

static void tree_index(node_t *node, long *last_index)
{
    if (node == NULL)
        return;

    nodes[*last_index] = node;
    node->data = (data_t) *last_index;
    ++(*last_index);

    tree_index(node->left, last_index);
    tree_index(node->right, last_index);
}

void dict_optimize()
{
    long last_index;

    if (nodes == NULL && tree != NULL) {
        nodes = (node_t **) malloc(sizeof(node_t *) * tree->size);
        last_index = 0L;
        tree_index(tree->root, &last_index);
        assert(last_index == tree->size);
    }
}

void dict_add(const char *key)
{
    int length, i;

    if (tree != NULL) {
        length = strlen(key);
        /* Stores each part. */
        for (i = 0; i < length; i += MAX_PART_SIZE)
            avl_insert(tree, key + i, DATA_NULL);
    }
}

int dict_search(const char *key)
{
    node_t *node;

    if (tree == NULL || (node = avl_search(tree, key)) == NULL)
        return -1;
    /* Returns the node index. */
    return (long) node->data;
}

int dict_mark(int index)
{
    if (nodes == NULL || nodes[index] == NULL)
        return 0;

    /* Ultra quickly access the node :D */
    node_t *node = nodes[index];
    nodes[index] = NULL;

    /* Remove from tree. */
    avl_remove(tree, node->key);

    return 1;
}

int dict_is_empty()
{
    return (tree != NULL && tree->size == 0);
}
